/********************************************************************************
* Description: socket addr wrapper, based on OOP method, this is a POD object
* Author: hsqiang
* Create Date: 2023-06-21
********************************************************************************/
#ifndef END_POINT_HPP_
#define END_POINT_HPP_

#include "assert_define.hpp"
#include <cstring>
#include <string.h>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>

namespace event_framework
{
    using Port = unsigned short;
    class EndPoint
    {
    public:
        EndPoint() = default;
        EndPoint(const std::string& ip, Port port)
        {
            bzero(&addr, sizeof addr);
            addr.sin_family = AF_INET;
            int ret = inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
            ASSERT(ret == 0);
            addr.sin_port = htons(port);
        }
        explicit EndPoint(const struct sockaddr_in& addr_) : addr(addr_) {}
        EndPoint(const EndPoint& ep)
        {
            if (this == &ep) return;
            addr = ep.addr;
        }
        EndPoint& operator=(const EndPoint& ep)
        {
            if (this == &ep) return *this;
            addr = ep.addr;
        }
        EndPoint(EndPoint&& ep)
        {
            if (this == &ep) return;
            addr = ep.addr;
        }
        EndPoint& operator=(EndPoint&& ep)
        {
            if (this == &ep) return *this;
            addr = ep.addr;
        }
        const struct sockaddr_in& GetAddr() const
        {
            return addr;
        }
        const struct sockaddr* GetAddrPtr() const
        {
            return (sockaddr*)&addr;
        }
        unsigned int GetAddrLen() const
        {
            return sizeof addr;
        }
        std::string GetIp() const
        {
            char buf[64];
            bzero(buf, sizeof buf);
            inet_ntop(addr.sin_family, (void*)&addr.sin_addr, buf, sizeof buf);
            return std::string(buf);
        }
        Port GetPort() const
        {
            return ntohs(addr.sin_port);
        }
    private:
        struct sockaddr_in addr;
    };

    inline std::ostream& operator<<(std::ostream& os, const EndPoint& ep)
    {
        os << ep.GetIp() << ":" << ep.GetPort();
        return os;
    }
}

#endif